package environment;

import java.io.Serializable;
import java.util.Random;

public class Application implements Serializable {
	
	public enum Type {
		WEBBASED, HPC, WEBBASED_HPC
	}
	
	private static final long serialVersionUID = 1L;
	private Integer id;
	private Integer loadCPUs;
	private Integer maxCPUs;
	
	private Integer cpuCycles;
	private boolean isRunning;
	private boolean isFinished;
	
	private VirtualMachine virtualMachine;
	
	private Type type;
	
	public Application(Integer id, Integer maxCPUs,
			Integer cpuCycles) {
		this.id = id;
		this.loadCPUs = 0;
		this.maxCPUs = maxCPUs;
		this.cpuCycles = cpuCycles;
		this.isRunning = false;
		this.isFinished = false;
	}
	
	public Application(Integer id, Type type) {
		Random random = new Random();
		
		int defaultCpuCyles = 10;
		
		this.id = id;
		this.loadCPUs = 0;

		if(type == Type.HPC)
			this.maxCPUs = random.nextInt(125) + 125;
		else if(type == Type.WEBBASED_HPC)
			this.maxCPUs = random.nextInt(75) + 50;
		else
			this.maxCPUs = random.nextInt(50) + 25;
			
		this.cpuCycles = (int) Math.abs(Math.round(random.nextGaussian() * 1 + defaultCpuCyles ));
		this.isRunning = false;
		this.isFinished = false;
		this.type = type;
	}
	
	public Integer getId() {
		return id;
	}
	public void setId(Integer id) {
		this.id = id;
	}
	public Integer getLoadCPUs() {
		return loadCPUs;
	}
	public void setLoadCPUs(Integer loadCPUs) {
		//adapt load of virtual machine
		if(virtualMachine!=null)
			virtualMachine.addLoadCPUs(loadCPUs-getLoadCPUs());
		this.loadCPUs = loadCPUs;
	}
	public Integer getMaxCPUs() {
		return maxCPUs;
	}
	public void setMaxCPUs(Integer maxCPUs) {
		this.maxCPUs = maxCPUs;
	}
	
	public VirtualMachine getVirtualMachine() {
		return virtualMachine;
	}
	public boolean isRunning() {
		return isRunning;
	}
	public void setRunning(boolean isRunning) {
		this.isRunning = isRunning;
	}
	public boolean isFinished() {
		return isFinished;
	}
	public void setFinished(boolean isFinished) {
		this.isFinished = isFinished;
	}

	public Type getType() {
		return type;
	}

	public void start()
	{
		setRunning(true);
		if(virtualMachine!=null)
		{
			virtualMachine.removeReservedCPUs(getMaxCPUs());
			virtualMachine.addMaxloadCPUs(getMaxCPUs());
		}
	}
	
	public void removeCPUCycle()
	{
		cpuCycles-=1;
	}
	
	public Integer getCpuCycles() {
		return cpuCycles;
	}

	public void stop()
	{
		setRunning(false); // not necessary, app will be removed
		setFinished(true);
		if(virtualMachine!=null)
		{
			virtualMachine.removeLoadCPUs(getLoadCPUs());
			virtualMachine.removeMaxloadCPUs(getMaxCPUs());
		}
	}
	
	public void setVirtualMachine(VirtualMachine virtualMachine) {
		if(this.virtualMachine != null)
		{
			this.virtualMachine.getApplications().remove(this);
			
			if(isRunning)
			{
				this.virtualMachine.removeLoadCPUs(getLoadCPUs());
				this.virtualMachine.removeMaxloadCPUs(getMaxCPUs());
			}
			else if(!isFinished)
				this.virtualMachine.removeReservedCPUs(getMaxCPUs());
		}
		
		this.virtualMachine = virtualMachine;
		
		if(virtualMachine != null && 
				!virtualMachine.getApplications().contains(this))
			virtualMachine.addApplication(this);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((id == null) ? 0 : id.hashCode());
		result = prime * result
				+ ((virtualMachine == null) ? 0 : virtualMachine.hashCode());
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Application other = (Application) obj;
		if (id == null) {
			if (other.id != null)
				return false;
		} else if (!id.equals(other.id))
			return false;
		if (virtualMachine == null) {
			if (other.virtualMachine != null)
				return false;
		} else if (!virtualMachine.equals(other.virtualMachine))
			return false;
		return true;
	}

	@Override
	public String toString() {
		return "Application [id=" + id + ", loadCPUs=" + loadCPUs
				+ ", maxCPUs=" + maxCPUs + ", cpuCycles=" + cpuCycles
				+ ", isRunning=" + isRunning + ", type=" + type + "]";
	}	
}
